#ifndef __TEMPLATE_HANDLER_H
#define __TEMPLATE_HANDLER_H

	#define ELEM_PLIST(type, pListIdx)		(elements[type][paintList[type][pListIdx]])
	#define GET_ELEM(shortVal)				(elements[((shortVal & (short)0xFF00) >> 8)][paintList[((shortVal & (short)0xFF00) >> 8)][shortVal & (short)0xFF]])

	static int tmplHandler_state 				= STATES.TEMPLATE_HANDLER_LOAD;
	static int tmplHandler_prevScreen			= 0;
	static int tmplHandler_curScreen 			= 0;
	static int tmplHandler_curScreenIdx			= 0;
	static boolean tmplHander_repaint 			= true;
	
	static cElement[][] elements;
	static cElement selectedElement;
	static cElement selectedMenu				= null;
	static cElement backgroundImage				= null;
	
	static int[][] paintList					= null;
	static int[][] menusList					= null;
	static int[][][] scrollViewList				= null; //EMY SCROLLVIEW
	static int[] menusListWidths				= null;
	static boolean paintingMenu					= false;
	
	static void tmplHandler_setScreen(int newScreen)
	{
		tmplHandler_prevScreen = tmplHandler_curScreen;
		tmplHandler_curScreen = newScreen;
		tmplHandler_state = STATES.TEMPLATE_HANDLER_CHANGE_SCREEN;
	}

	void updateTemplateHandler()
	{
		switch(tmplHandler_state)
		{
			case STATES.TEMPLATE_HANDLER_LOAD:
			{				
				LoadFile("offside.bjae");				
				tmplHandler_curScreen = elements[ELEM_TYPES.APP][0].intProps[PROPS.IIDX_EP];
								
				tmplHandler_state = STATES.TEMPLATE_HANDLER_CHANGE_SCREEN;
			}
			break;
			
			case STATES.TEMPLATE_HANDLER_CHANGE_SCREEN:
			{				
				tmplHandler_reset();
				
				LoadControls();
				
				for(int i = 0; i < elements[ELEM_TYPES.SCR].length; i++)
				{
					if(elements[ELEM_TYPES.SCR][i].intProps[PROPS.IIDX_ID] == tmplHandler_curScreen)
					{
						tmplHandler_curScreenIdx = i;
						break;
					}
				}
			
				tmplHander_repaint = true;
				tmplHandler_state = STATES.TEMPLATE_HANDLER_RUN;
			}
			break;
			
			case STATES.TEMPLATE_HANDLER_RUN:
			{				
				if(tmplHander_repaint)
				{	
					tmplHander_repaint = false;
					
					if(elements[ELEM_TYPES.SCR][tmplHandler_curScreenIdx].isFlagEnabled(PROPS.FLG_REPAINT_BACKGROUND) && !paintingMenu)
					{
						if(backgroundImage == null)
						{
							cGame_g.setColor(elements[ELEM_TYPES.SCR][tmplHandler_curScreenIdx].intProps[PROPS.IIDX_BGC]);
							cGame_g.setClip(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
							cGame_g.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
						}
						else
						{
							cGame_g.setColor(elements[ELEM_TYPES.SCR][tmplHandler_curScreenIdx].intProps[PROPS.IIDX_BGC]);
							cGame_g.setClip(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
							cGame_g.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
							backgroundImage.Draw(cGame_g, false);
						}
					}
				
					for(int i = 0; i < menusList.length; i++)
					{
						if(ELEM_PLIST(ELEM_TYPES.MNU, i).strProps[PROPS.SIDX_MTP].equalsIgnoreCase("TB")) // tab menu
						{
							ELEM_PLIST(ELEM_TYPES.MNU, i).DrawMenu(cGame_g, selectedElement == ELEM_PLIST(ELEM_TYPES.MNU, i));
						}
					}

					for(int i = 0; i < scrollViewList.length; i++)	//EMY SCROLLVIEW
					{
						ELEM_PLIST(ELEM_TYPES.SCV, i).DrawScrollView(cGame_g);
					}
					if(!paintingMenu)
					{
						for(int i = ELEM_TYPES.COUNT - 1; i >= ELEM_TYPES.BTN; i--)
						{
							for(int j = 0; j < paintList[i].length; j++)
							{
								if(ELEM_PLIST(i, j).isFlagEnabled(PROPS.FLG_ENABLED) || ELEM_PLIST(i, j).isFlagEnabled(PROPS.FLG_VISIBLE_DISABLED))
								{
									ELEM_PLIST(i, j).Draw(cGame_g, selectedElement == ELEM_PLIST(i, j));
								}
							}
						}
					}
				}
				
				if(curAction >= ACTIONS.UP && curAction <= ACTIONS.RIGHT && selectedElement != null)
				{
					if(!paintingMenu)
					{
						switch(curAction)
						{
							case ACTIONS.UP:
								if(selectedElement.bounds[PROPS.BOUND_UP] != PROPS.DEFAULT_BOUND)
								{
									selectedElement = ELEM_PLIST(selectedElement.bounds[PROPS.BOUND_UP] >> 8 & (short)0xFF, selectedElement.bounds[PROPS.BOUND_UP] & (short)0xFF);
									tmplHander_repaint = true;
								}
							break;
							
							case ACTIONS.DOWN:
								if(selectedElement.bounds[PROPS.BOUND_DOWN] != PROPS.DEFAULT_BOUND)
								{
									selectedElement = ELEM_PLIST(selectedElement.bounds[PROPS.BOUND_DOWN] >> 8 & (short)0xFF, selectedElement.bounds[PROPS.BOUND_DOWN] & (short)0xFF);
									tmplHander_repaint = true;
								}
							break;
							
							case ACTIONS.LEFT:
								if(selectedElement.bounds[PROPS.BOUND_LEFT] != PROPS.DEFAULT_BOUND)
								{
									selectedElement = ELEM_PLIST(selectedElement.bounds[PROPS.BOUND_LEFT] >> 8 & (short)0xFF, selectedElement.bounds[PROPS.BOUND_LEFT] & (short)0xFF);
									tmplHander_repaint = true;
								}
							break;
							
							case ACTIONS.RIGHT:
								if(selectedElement.bounds[PROPS.BOUND_RIGHT] != PROPS.DEFAULT_BOUND)
								{
									selectedElement = ELEM_PLIST(selectedElement.bounds[PROPS.BOUND_RIGHT] >> 8 & (short)0xFF, selectedElement.bounds[PROPS.BOUND_RIGHT] & (short)0xFF);
									tmplHander_repaint = true;
								}
							break;
						}
					}
					else
					{
						switch(curAction)
						{
							case ACTIONS.UP:
								if(selectedMenu != null && selectedMenu.selIndex > 0)
								{
									selectedMenu.selIndex--;
									tmplHander_repaint = true;
								}
							break;
							
							case ACTIONS.DOWN:
								if(selectedMenu != null && selectedMenu.selIndex < selectedMenu.childs - 1)
								{
									selectedMenu.selIndex++;
									tmplHander_repaint = true;
								}
							break;
						}
					}
				}

				if(selectedMenu == null)
				{
					for(int i = ELEM_TYPES.MNU; i < ELEM_TYPES.COUNT; i++)
					{
						boolean stopUpdate = false;
						for(int j = 0; j < paintList[i].length; j++)
						{
							if(ELEM_PLIST(i, j).isFlagEnabled(PROPS.FLG_ENABLED))
							{
								if(ELEM_PLIST(i, j).update(curAction))
								{
									stopUpdate = true;
									break;
								}
							}
						}
						
						if(stopUpdate)
						{
							break;
						}
					}
				}
				else
				{
					selectedMenu.update(curAction);
				}
			}
			break;
		}
	}
	
	static void performActions(int[] actionsIds, int[] actionParamsInt, String[] actionParamsStr)
	{
		for(int i = 0; i < actionsIds.length; i++)
		{
			switch(actionsIds[i] & ACTIONS.MASK)
			{
				case ACTIONS.SET_SCREEN:
				{
					tmplHandler_setScreen(actionsIds[i]);
				}
				break;
				
				case ACTIONS.APP_MESSAGE:
				{
					switch(actionsIds[i] & ~ACTIONS.MASK)
					{
						case ACTIONS.APPM_EXIT:
						{
							started = false;
						}
						break;
						
						case ACTIONS.APPM_PLREQ:
						{
							if (APP_CONFIG.platformRequestType == APP_CONFIG.PLATFORM_REQUEST_ON_PAINT)
			                {
			                    try
			                    {
			                    	//TODO: TOMAR LA URL DE ALGUN PARAMETRO DEL BOTON
			                    	midlet_instance.platformRequest(actionParamsStr[0]);

			                        if (APP_CONFIG.destroyApplicationAfterPlatformRequest)
			                        {
			                        	started = false;
			                        }
			                    }
			                    catch (ConnectionNotFoundException e) {}
			                }
			                else if (APP_CONFIG.platformRequestType == APP_CONFIG.PLATFORM_REQUEST_ON_NEW_THREAD)
			                {
//			                    platformRequestOnNewThread = true;
//			                	TODO: IMPLEMENTAME.
			                }
						}
						break;
						//TODO: SIIII ESTA RE SUCIO PERO LO VOY A LIMPIARRRR
						case ACTIONS.APPM_SMS:
						{
							//prepareSMS();
							
							final String tkb = actionParamsStr[0];
							new Thread()
			                {
			                    public void run()
			                    {
			                    	if(!isSMSSent)
			                    	{
				                        MessageConnection conn = null;
				                        TextMessage sms;
	
				                        try
				                        {
				                            String smsNumber = "";
	
				                            if (APP_CONFIG.enableSMSHeader)
				                            {
				                                smsNumber = "sms:/" + "/";
				                            }
	
				                            {
				                                smsNumber += "+5491150519645"; //TODO: TOMARLO DEL IMPUT TEXTBOX
				                            }
	
				                            conn = (MessageConnection) Connector.open(smsNumber);
	
				                            sms = (TextMessage) conn.newMessage(MessageConnection.TEXT_MESSAGE);
	
				                            sms.setPayloadText(tkb);
	
				                            try
				                            {
				                                Thread.sleep(200);
				                            }
				                            catch(Exception e) {}
	
				                            conn.send(sms);
	
				                            isSMSSent = true;
	
				                            try
				                            {
				                                Thread.sleep(100);
				                            }
				                            catch(Exception e) {}
				                        }
				                        catch(Exception e)
				                        {
				                            isSMSSent = false;
				                            cGame.error = new String ("SMS sent failed " + __FILE__ + " " + __LINE__);
				                        }
	
				                        try
				                        {
				                            conn.close();
				                        }
				                        catch(Exception e)
				                        {
				                        	cGame.error = new String ("Failed to close connection " + __FILE__ + " " + __LINE__);
				                        }
	
				                        tmplHander_repaint = true;
				                        tmplHandler_state = STATES.TEMPLATE_HANDLER_RUN;
			                    	} //if(!isSMSSent)
			                    };
			                }.start();
						}
						break;
					} //switch(actionsIds[i] & ~ACTIONS.MASK)
				}
				break;
			}
		}
	}
	
	static void tmplHandler_reset()
	{
		for(int i = 0; i < elements[ELEM_TYPES.MNU].length; i++)
		{
			elements[ELEM_TYPES.MNU][i].state = ELEM_STATES.MNU_CLOSED;
			elements[ELEM_TYPES.MNU][i].selIndex = 0;
		}
		
		for(int i = 0; i < elements.length; i++)
		{
			for(int j = 0; j < elements[i].length; j++)
			{
				elements[i][j].img = null;
			}
		}
	
		backgroundImage = null;
		selectedElement = null;
		selectedMenu = null;
		paintList = null;
		menusList = null;
		scrollViewList = null; //EMY SCROLLVIEW
		menusListWidths = null;
		paintingMenu = false;
	}
	
	void LoadControls()
	{
		int menus = 0;
		int scvs = 0; // scroll views //EMY SCROLLVIEW
		
		// crea una matriz de pintado con una columna para cada tipo de elemento. 
		paintList = new int[ELEM_TYPES.COUNT][];
		
		// count the number of menus to be painted in the current screen
		for(int i = 0; i < elements[ELEM_TYPES.MNU].length; i++)
		{
			if(elements[ELEM_TYPES.MNU][i].intProps[PROPS.IIDX_FTR] == tmplHandler_curScreen
			|| elements[ELEM_TYPES.MNU][i].isFlagEnabled(PROPS.FLG_IN_ALL_SCREENS))
			{
				menus++;
			}
		}

		for(int i = 0; i < elements[ELEM_TYPES.SCV].length; i++) //EMY SCROLLVIEW
		{
			if (elements[ELEM_TYPES.SCV][i].intProps[PROPS.IIDX_FTR] == tmplHandler_curScreen)
			{
				scvs++;
			}
		}
		
		// crea una matriz para meter todos los elementos de los menues que se van a apintar en la pantalla actual. 
		menusList = new int[menus][];
		scrollViewList = new int [scvs][ELEM_TYPES.COUNT][]; //EMY SCROLLVIEW
		
		// crea una lista para saber el ancho de cada menu.
		menusListWidths = new int[menus];
		paintList[ELEM_TYPES.MNU] = new int[menus];
		paintList[ELEM_TYPES.SCV] = new int[scvs]; //EMY SCROLLVIEW

		menus = 0;
		scvs = 0; //EMY SCROLLVIEW
		
		// DIDI - TEMP HARDCODE // REMOVE LATER
		// le asigna el ancho a cada menu (les rparte la pantalla)
		for(int i = 0; i < menusListWidths.length; i++)
		{
			menusListWidths[i] = SCREEN_WIDTH / menusListWidths.length;
		}
		
		int menuX = 0;
		
		// recorre nuevamente todos los elementos que son menues dentro de la matriz de elementos, se guardan los indices que los ubican en la 
		// dicha matriz de aquellos que son especificos de la pantalla actual o son de todas las panatallas.
		// ademas va calculando el X donde empezaria cada menu.
		// get the indexes from the elements array of the menus to be drawn
		for(int i = 0; i < elements[ELEM_TYPES.MNU].length; i++)
		{
			if(elements[ELEM_TYPES.MNU][i].intProps[PROPS.IIDX_FTR] == tmplHandler_curScreen
			|| elements[ELEM_TYPES.MNU][i].isFlagEnabled(PROPS.FLG_IN_ALL_SCREENS))
			{
				paintList[ELEM_TYPES.MNU][menus++] = i;
				elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][menus - 1]].intProps[PROPS.IIDX_RCX] = menuX;
				elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][menus - 1]].intProps[PROPS.IIDX_RCY] = 0;
				elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][menus - 1]].intProps[PROPS.IIDX_RCW] = menusListWidths[i];
				elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][menus - 1]].intProps[PROPS.IIDX_RCH] = SCRH_PER(10);
				menuX += menusListWidths[i];
			}
		}

		// Por ahora consideramos que habra una sola scroll view por pantalla, por lo tanto el siguiente codigo estari de mas.
		for(int i = 0; i < elements[ELEM_TYPES.SCV].length; i++) //EMY SCROLLVIEW
		{
			if(elements[ELEM_TYPES.SCV][i].intProps[PROPS.IIDX_FTR] == tmplHandler_curScreen)
			{
				paintList[ELEM_TYPES.SCV][scvs] = i;
				elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][scvs]].intProps[PROPS.IIDX_RCX] = elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][scvs]].intProps[PROPS.IIDX_RCX] * 100 / SCREEN_WIDTH;
				elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][scvs]].intProps[PROPS.IIDX_RCY] = elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][scvs]].intProps[PROPS.IIDX_RCY] * 100 / SCREEN_HEIGHT;
				elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][scvs]].intProps[PROPS.IIDX_RCW] = elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][scvs]].intProps[PROPS.IIDX_RCW] * 100 / SCREEN_WIDTH;
				elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][scvs]].intProps[PROPS.IIDX_RCH] = elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][scvs]].intProps[PROPS.IIDX_RCH] * 100 / SCREEN_HEIGHT;
				scvs++;
				menuX += menusListWidths[i];
			}
		}

		// HASTA ACA SE TIENE: 
		// 		LA PAINTLIST CON LOS INDICES DE LOS MENUS DENTRO DE ELEMENTS.
		// 		LOS ANCHOS DE CADA MENU.
		//		LOS X DONDE EMPIEZA CADA MENU.
		
		int curMenuBtnCount = 0;
		int maxStringWidth = 0;
		
		// recorre la lista de pintado de menues y la matriz de elementos, y pregunta si el elemento tiene como padre a alguno de los menues que estan en 
		// la lista de pintado de menues.
		// fill menusList and buttons paintList
		for(int i = 0; i < paintList[ELEM_TYPES.MNU].length; i++)
		{
			curMenuBtnCount = 0;
			
			maxStringWidth = 0;
			
			for(int j = 0; j < elements[ELEM_TYPES.BTN].length; j++)
			{
				if(elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_FTR] == elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][i]].intProps[PROPS.IIDX_ID])
				{
					curMenuBtnCount++;
					// se fija si el ancho del string de ese elemento es mayor al que estaba como maximo ancho y si es asi lo reemplaza.
					if(!elements[ELEM_TYPES.BTN][j].isFlagEnabled(PROPS.FLG_SCROLL_HORIZONTALLY) && cGame_g.getStringWidth(elements[ELEM_TYPES.BTN][j].strProps[PROPS.SIDX_NAME]) > maxStringWidth)
					{
						maxStringWidth = cGame_g.getStringWidth(elements[ELEM_TYPES.BTN][j].strProps[PROPS.SIDX_NAME]);
					}
				}
			}
			
			maxStringWidth += (SCRW_PER(2) * 2);
			
			// agrega en la matriz de elementos cuantos hijos tiene el menu.
			elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][i]].childs = curMenuBtnCount;
			menusList[i] = new int[curMenuBtnCount];
			curMenuBtnCount = 0;
			
			// Vuelve a recorrer todos los botones de la matriz de elementos y si tienen a algun menu como padre se agregan a la lista de pintado.
			for(int j = 0; j < elements[ELEM_TYPES.BTN].length; j++)
			{
				if(elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_FTR] == elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][i]].intProps[PROPS.IIDX_ID])
				{
					// actualiza la posicion de los elementos.
					elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_RCX] = elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][i]].intProps[PROPS.IIDX_RCX] + elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][i]].intProps[PROPS.IIDX_RCW] / 2 - maxStringWidth / 2;
					if(elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_RCX] < 0)
					{
						elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_RCX] = 0;
					}
					else if(elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_RCX] + maxStringWidth > SCREEN_WIDTH)
					{
						elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_RCX] = SCREEN_WIDTH - maxStringWidth;
					}
					elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_RCW] = maxStringWidth;
					elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_RCH] = elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][i]].intProps[PROPS.IIDX_RCH];
					elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_RCY] = elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][i]].intProps[PROPS.IIDX_RCY] + elements[ELEM_TYPES.MNU][paintList[ELEM_TYPES.MNU][i]].intProps[PROPS.IIDX_RCH] + curMenuBtnCount * elements[ELEM_TYPES.BTN][j].intProps[PROPS.IIDX_RCH];
					menusList[i][curMenuBtnCount++] = j;
				}
			}
		}
		
		int itemX = 0; //EMY SCROLLVIEW
		int itemY = 0;
		int itemW = 0;
		int itemCount = 0;
		int totalItemCount = 0;
		
		for(int i = 0; i < paintList[ELEM_TYPES.SCV].length; i++)  //EMY SCROLLVIEW
		{
			itemCount = 0;
			totalItemCount = 0;

			itemX = elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][i]].intProps[PROPS.IIDX_RCX];
			itemY = elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][i]].intProps[PROPS.IIDX_RCY];
			itemW = elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][i]].intProps[PROPS.IIDX_RCW];
			
			for (int k = ELEM_TYPES.BTN ; k <= ELEM_TYPES.IMG ; ++k )
			{
				for(int j = 0; j < elements[k].length; j++)
				{
					if(elements[k][j].intProps[PROPS.IIDX_FTR] == elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][i]].intProps[PROPS.IIDX_ID])
					{
						itemCount++;
					}
				}
				totalItemCount += itemCount;
				scrollViewList[i][k] = new int[itemCount];
				itemCount = 0;
			}
			
			// agrega en la matriz de elementos cuantos hijos tiene la scv.
			elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][i]].childs = totalItemCount;
			
			itemCount = 0;
			totalItemCount = 0;
			
			for (int k = ELEM_TYPES.BTN ; k <= ELEM_TYPES.IMG ; ++k )
			{
				for(int j = 0; j < elements[k].length ; j++)
				{
					if(elements[k][j].intProps[PROPS.IIDX_FTR] == elements[ELEM_TYPES.SCV][paintList[ELEM_TYPES.SCV][i]].intProps[PROPS.IIDX_ID])
					{
						// actualiza la posicion de los elementos.
						elements[k][j].intProps[PROPS.IIDX_RCX] = itemX;
						
						elements[k][j].intProps[PROPS.IIDX_RCW] = itemW;
						// La altura la dejo como esta.
						elements[k][j].intProps[PROPS.IIDX_RCH] = elements[k][j].intProps[PROPS.IIDX_RCH];
						
						elements[k][j].intProps[PROPS.IIDX_RCY] = itemY;
						
						itemY += elements[k][j].intProps[PROPS.IIDX_RCH];
						
						scrollViewList[i][k][itemCount++] = j;
					}
				}
				itemCount = 0;
			}
		}
		
		// HASTA ACA SE TIENE: 
		// 		LA PAINTLIST CON LOS INDICES DE LOS MENUS DENTRO DE ELEMENTS.
		// 		LOS ANCHOS DE CADA MENU.
		//		LOS X DONDE EMPIEZA CADA MENU.
		// 		TODOS LOS ELEMENTOS QUE SON HIJOS DE LOS MENUES A PINTAR
		//		LAS POSICIONES Y DIMENSIONES DE TALES ELEMENTOS ACTUALIZADA.
		
		// recorre desde los elementos del tipo boton hacia arriba (hasta imagenes) la matriz de elementos preguntando si tienen como padre a la pantalla 
		// actual.
		
		for(int j = ELEM_TYPES.BTN; j < ELEM_TYPES.COUNT; j++)
		{
			int controls = 0;
			
			for(int k = 0; k < elements[j].length; k++)
			{
				if(elements[j][k].intProps[PROPS.IIDX_FTR] == tmplHandler_curScreen
				|| elements[j][k].isFlagEnabled(PROPS.FLG_IN_ALL_SCREENS))
				{
					if(!elements[j][k].isFlagEnabled(PROPS.FLG_IS_BACKGROUND_IMAGE))
					{
						controls++;
					}
				}
			}
			
			paintList[j] = new int[controls];
			controls = 0;
			
			for(int k = 0; k < elements[j].length; k++)
			{
				if(elements[j][k].intProps[PROPS.IIDX_FTR] == tmplHandler_curScreen
				|| elements[j][k].isFlagEnabled(PROPS.FLG_IN_ALL_SCREENS))
				{
					if(!elements[j][k].isFlagEnabled(PROPS.FLG_IS_BACKGROUND_IMAGE))
					{
						paintList[j][controls++] = k;
					}
					else
					{
						backgroundImage = elements[j][k];
					}
				}
			}
		}
		// navigation		
		for(int i = ELEM_TYPES.MNU; i < paintList.length; i++)
		{		
			for(int j = 0; j < paintList[i].length; j++)
			{			
				int minUp = 500;
				int minDown = 500;
				int minLeft = -500;
				int minRight = 500;
				
				short minElemUp = PROPS.DEFAULT_BOUND;
				short minElemDown = PROPS.DEFAULT_BOUND;
				short minElemLeft = PROPS.DEFAULT_BOUND;
				short minElemRight = PROPS.DEFAULT_BOUND;
				
				if(ELEM_PLIST(i, j).isFlagEnabled(PROPS.FLG_TAB_INDEX))
				{
					for(int k = ELEM_TYPES.MNU; k < paintList.length; k++)
					{
						for(int m = 0; m < paintList[k].length; m++)
						{
							if(!(m == j && k == i) && ELEM_PLIST(k, m).isFlagEnabled(PROPS.FLG_TAB_INDEX))
							{
								int xDiff = ELEM_PLIST(k, m).intProps[PROPS.IIDX_RCX] - ELEM_PLIST(i, j).intProps[PROPS.IIDX_RCX];
								int yDiff = ELEM_PLIST(k, m).intProps[PROPS.IIDX_RCY] - ELEM_PLIST(i, j).intProps[PROPS.IIDX_RCY];
								if(xDiff > SCRW_PER(7) && ABS(xDiff) < minRight)
								{
									if(ABS(yDiff) < SCRH_PER(5))
									{
										minRight = ABS(xDiff);
										minElemRight = MAKE_SHORT_ID(k, m);
									}
									else
									{
										if(yDiff > 0)
										{
											minDown = ABS(yDiff);
											minElemDown = MAKE_SHORT_ID(k, m);
										}
										else
										{
											minUp = ABS(yDiff);
											minElemUp = MAKE_SHORT_ID(k, m);
										}
									}
								}
								else if(xDiff < (0 - SCRW_PER(7)) && xDiff > minLeft)
								{
									if(ABS(yDiff) < SCRH_PER(5))
									{
										minLeft = xDiff;
										minElemLeft = MAKE_SHORT_ID(k, m);
									}
									else
									{
										if(yDiff > 0)
										{
											minDown = ABS(yDiff);
											minElemDown = MAKE_SHORT_ID(k, m);
										}
										else
										{
											minUp = ABS(yDiff);
											minElemUp = MAKE_SHORT_ID(k, m);
										}
									}
								}
								else if(yDiff > SCRH_PER(5) && ABS(xDiff) < SCRW_PER(7) && ABS(yDiff) < minDown)
								{
									minDown = ABS(yDiff);
									minElemDown = MAKE_SHORT_ID(k, m);
								}							
								else if(yDiff < (0 - SCRH_PER(5)) && ABS(xDiff) < SCRW_PER(7) && ABS(yDiff) < minUp)
								{
									minUp = ABS(yDiff);
									minElemUp = MAKE_SHORT_ID(k, m);
								}
							}
						}
					}
				}
				
				ELEM_PLIST(i, j).SET_BOUND(PROPS.BOUND_UP, minElemUp >> 8, minElemUp & 0xFF);
				ELEM_PLIST(i, j).SET_BOUND(PROPS.BOUND_DOWN, minElemDown >> 8, minElemDown & 0xFF);
				ELEM_PLIST(i, j).SET_BOUND(PROPS.BOUND_LEFT, minElemLeft >> 8, minElemLeft & 0xFF);
				ELEM_PLIST(i, j).SET_BOUND(PROPS.BOUND_RIGHT, minElemRight >> 8, minElemRight & 0xFF);
			}
		}
		
		int minX = 500;
		int minY = 500;
		for(int i = ELEM_TYPES.MNU; i < paintList.length; i++)
		{
			for(int j = 0; j < paintList[i].length; j++)
			{
				if(ELEM_PLIST(i, j).intProps[PROPS.IIDX_RCX] < minX && ELEM_PLIST(i, j).intProps[PROPS.IIDX_RCY] < minY && ELEM_PLIST(i, j).isFlagEnabled(PROPS.FLG_TAB_INDEX))
				{
					minX = ELEM_PLIST(i, j).intProps[PROPS.IIDX_RCX];
					minY = ELEM_PLIST(i, j).intProps[PROPS.IIDX_RCY];
					selectedElement = ELEM_PLIST(i, j);
				}
			}
		}
	}
	
	byte[] ISToByteArray(InputStream is)
	{		
		byte[] array = null;
		try
		{
			array = new byte[is.available()];
			
			int i = 0;		
			while(is.available() != 0)
			{
				array[i] = (byte)is.read();
				i++;
			}
		}
		catch(Exception e)
		{
			cGame.error = "InputStreamException " + __FILE__ + " " + __LINE__;
		}
		return array;
	}

	byte readByte(byte[] file)
	{
		int off = fileOff;
		fileOff++;
		return file[off];
	}
	
	byte[] readBytes(byte[] file, int count)
	{
		int off = fileOff;
		fileOff += count;
		
		byte[] result = new byte[count];
		int i = 0;
		
		try
		{
			for(i = 0; i < count; i++)
			{
				result[i] = file[off];
				off++;
			}
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			cGame.error = "ArrayIndexOOB: " + i + " in " + __FILE__ + " " + __LINE__;
		}
		
		return result;
	}
	
	int readInt(byte[] file)
	{
		int off = fileOff;
		fileOff += 4;
		int theInt = 0;
		int i = 0;
		
		try
		{
			for(i = fileOff - 1; i >= off; i--)
			{
				theInt = (theInt << 8) | ((int)file[i] & 0xFF);
			}
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			cGame.error = "ArrayIndexOOB: " + i + " in " + __FILE__ + " " + __LINE__;
		}
		
		return theInt;
	}
	
	int fileOff = 0;
	
	void LoadFile(String fileName)
	{
		elements = new cElement[ELEM_TYPES.COUNT][];
		byte[] file = null;
	
		try
		{
			InputStream def = getClass().getResourceAsStream(fileName);
			file = ISToByteArray(def);
			def.close();
		}
		catch(Exception e)
		{
			cGame.error = "InputStream failed open: " + fileName + " in " + __FILE__ + " " + __LINE__;
		}
		
		for(int i = 0; i < ELEM_TYPES.COUNT; i++)
		{
			elements[i] = new cElement[readByte(file)];
			for(byte j = 0; j < elements[i].length; j++)
			{
				elements[i][j] = new cElement(i);
				for(int k = 0; k < PROPS.IINDEXES[i].length; k++)
				{
					if(PROPS.IINDEXES[i][k] < PROPS.IIDX_RCX || PROPS.IINDEXES[i][k] > PROPS.IIDX_RCH)
					{
						elements[i][j].intProps[PROPS.IINDEXES[i][k]] = readInt(file);
					}
					else
					{
						elements[i][j].intProps[PROPS.IINDEXES[i][k]] = readByte(file);
					}
				}				
				
				if(i == ELEM_TYPES.BTN || i == ELEM_TYPES.IMG)
				{
					elements[i][j].actions = new int[readByte(file)];
					for(int act = 0; act < elements[i][j].actions.length; act++)
					{
						elements[i][j].actions[act] = readInt(file);
					}
				}
				
				for(int k = 0; k < PROPS.SINDEXES_LEN[i]; k++)
				{
					byte len = readByte(file);
					elements[i][j].strProps[PROPS.SINDEXES[i][k]] = new String(readBytes(file, len));
				}
				
				byte fParamCount = readByte(file);
				
				for(int k = 0; k < fParamCount; k++)
				{
					byte paramCount = readByte(file);
					
					int curParamInt = 0;
					int curParamStr = 0;
					
					for(int l = 0; l < paramCount; l++)
					{
						byte type = readByte(file);
						
						switch(type)
						{
								case PROPS.FTYPE_INT:
								case PROPS.FTYPE_HEX_STRING:
								case PROPS.FTYPE_APP_COMBO:
								case PROPS.FTYPE_SCR_COMBO:
								case PROPS.FTYPE_ALL_COMBO:
								case PROPS.FTYPE_ACTBIND_COMBO:
								case PROPS.FTYPE_FRM_BUTTON_FLAGS:
								case PROPS.FTYPE_FRM_BUTTON_ACTIONS:
								case PROPS.FTYPE_FLAG_PARAMS:
									elements[i][j].intFlagsParams[curParamInt] = readInt(file);
									curParamInt++;
								break;
								
								case PROPS.FTYPE_STRING:
								case PROPS.FTYPE_MNUTYPE_COMBO:
								case PROPS.FTYPE_TXTYPE_COMBO:
									String paramValue = "";
									
									byte fParamStrLen = readByte(file);
									
									for(int __i = 0; __i < fParamStrLen; __i++)
									{
										paramValue += ((char)readByte(file));
									}
									
									elements[i][j].strFlagsParams[curParamStr] = paramValue;
									curParamStr++;
								break;
						}
					}
				}
				
				if(i == ELEM_TYPES.BTN || i == ELEM_TYPES.IMG)
				{
					byte aParamCount = readByte(file);
					elements[i][j].intActionsParams = new int[16];
					elements[i][j].strActionsParams = new String[16];
											
					int curParamInt = 0;
					int curParamStr = 0;
					
					for(int k = 0; k < aParamCount; k++)
					{
						byte paramCount = readByte(file);
						
						for(int l = 0; l < paramCount; l++)
						{
							byte type = readByte(file);
							
							switch(type)
							{
									case PROPS.FTYPE_INT:
									case PROPS.FTYPE_HEX_STRING:
									case PROPS.FTYPE_APP_COMBO:
									case PROPS.FTYPE_SCR_COMBO:
									case PROPS.FTYPE_SCR_MNU_COMBO:
									case PROPS.FTYPE_ACTBIND_COMBO:
									case PROPS.FTYPE_FRM_BUTTON_FLAGS:
									case PROPS.FTYPE_FRM_BUTTON_ACTIONS:
									case PROPS.FTYPE_FLAG_PARAMS:
										elements[i][j].intActionsParams[curParamInt] = readInt(file);
										curParamInt++;
									break;
									
									case PROPS.FTYPE_STRING:
									case PROPS.FTYPE_MNUTYPE_COMBO:
									case PROPS.FTYPE_TXTYPE_COMBO:
										String paramValue = "";
										
										byte fParamStrLen = readByte(file);
										
										for(int __i = 0; __i < fParamStrLen; __i++)
										{
											paramValue += ((char)readByte(file));
										}
										
										elements[i][j].strActionsParams[curParamStr] = paramValue;
										System.out.println("asd " + j + "  " + curParamStr + " " + elements[i][j].strActionsParams[curParamStr]);
										curParamStr++;
									break;
									
									case PROPS.FTYPE_PLATFORM_REQ_COMBO:
										elements[i][j].intActionsParams[curParamInt] = readByte(file);
										curParamInt++;
									break;
									
									case PROPS.FTYPE_PROPS_COMBO:
										elements[i][j].intActionsParams[curParamInt] = readInt(file);
										curParamInt++;
										elements[i][j].intActionsParams[curParamInt] = readByte(file);
										if(elements[i][j].intActionsParams[curParamInt] == -1)
										{
											curParamInt++;
											break;
										}
										curParamInt++;
										elements[i][j].intActionsParams[curParamInt] = readByte(file);
										curParamInt++;
									break;
							}
						}
					}
				}
			}
		}

		for(int j = ELEM_TYPES.BTN; j < ELEM_TYPES.COUNT; j++)
		{
			for(int i = 0; i < elements[j].length; i++)
			{
				elements[j][i].intProps[PROPS.IIDX_RCX] = elements[j][i].intProps[PROPS.IIDX_RCX] * SCREEN_WIDTH / 100;
				elements[j][i].intProps[PROPS.IIDX_RCY] = elements[j][i].intProps[PROPS.IIDX_RCY] * SCREEN_HEIGHT / 100;
				elements[j][i].intProps[PROPS.IIDX_RCW] = elements[j][i].intProps[PROPS.IIDX_RCW] * SCREEN_WIDTH / 100;
				elements[j][i].intProps[PROPS.IIDX_RCH] = elements[j][i].intProps[PROPS.IIDX_RCH] * SCREEN_HEIGHT / 100;
			}
		}
		
		for(int j = ELEM_TYPES.SCR; j < ELEM_TYPES.COUNT; j++)
		{
			for(int i = 0; i < elements[j].length; i++)
			{
				for(int k = PROPS.IIDX_BGC; k <= PROPS.IIDX_AFC; k++)
				{
					if(elements[j][i].intProps[k] == PROPS.INHERIT_COLOR)
					{
						elements[j][i].intProps[k] = getElementById(elements[j][i].intProps[PROPS.IIDX_FTR]).intProps[k];
					}
				}
			}
		}
	}
	
	cElement getElementById(int elemId)
	{
		for(int i = 0; i < elements.length; i++)
		{
			for(int j = 0; j < elements[i].length; j++)
			{
				if(elements[i][j].intProps[PROPS.IIDX_ID] == elemId)
				{
					return elements[i][j];
				}
			}
		}
		
		return null;
	}
	
#endif // __TEMPLATE_HANDLER_H